package com.supconit.kqfx.web.fxzf.avro.redis.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

import com.supconit.honeycomb.business.authorization.services.RoleService;
import com.supconit.kqfx.web.fxzf.channel.entities.Channel;
import com.supconit.kqfx.web.fxzf.channel.services.ChannelService;
import com.supconit.kqfx.web.fxzf.msg.services.PushMsgFlagService;
import com.supconit.kqfx.web.fxzf.search.entities.Vehicle;
import com.supconit.kqfx.web.fxzf.search.services.FxzfStaticService;
import com.supconit.kqfx.web.fxzf.search.services.Impl.VehicleServiceImpl;
import com.supconit.kqfx.web.fxzf.search.services.VehicleService;
import com.supconit.kqfx.web.util.*;
import com.supconit.kqfx.web.xtgl.services.ExtUserService;
import jodd.util.StringUtil;

import org.apache.avro.io.DatumReader;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import redis.clients.jedis.Jedis;

import com.supconit.kqfx.web.device.entities.Redis_DeviceData;
import com.supconit.kqfx.web.fxzf.avro.redis_BoardData;
import com.supconit.kqfx.web.fxzf.avro.redis_FxzfInfo;
import com.supconit.kqfx.web.fxzf.avro.redis.ReadRedisService;
import com.supconit.kqfx.web.fxzf.avro.redis.WriteRedisService;
import com.supconit.kqfx.web.fxzf.search.entities.Fxzf;
import com.supconit.kqfx.web.fxzf.search.services.FxzfSearchService;
import com.supconit.kqfx.web.fxzf.search.services.IllegalTrailService;
import com.supconit.kqfx.web.fxzf.warn.entities.WarnInfo;
import com.supconit.kqfx.web.fxzf.warn.services.ConfigService;
import com.supconit.kqfx.web.fxzf.warn.services.WarnHistoryService;
import com.supconit.kqfx.web.fxzf.warn.services.WarnInfoService;
import com.supconit.kqfx.web.list.services.BlackListService;

/**
 * 从redis中读取内容显示
 * @author gs
 */
@Service("avro_readredis_service")
public class ReadRedisServiceImpl implements ReadRedisService {

	private static final Logger logger = LoggerFactory.getLogger(ReadRedisServiceImpl.class);

	private static final String BoardData_Prefix = "QBB_INFO_0";

	private static final String FxzfInfo = "FXZF_DATA_DY";

	private static final String FXZF_STATIC="FXZF_DATA";

	private static final BlockingQueue<Fxzf> fxzfQueue = new ArrayBlockingQueue<Fxzf>(5000);

	private static final BlockingQueue<String> fxzfMessage = new ArrayBlockingQueue<String>(500);

	private ExecutorService executorService = Executors.newCachedThreadPool();

	private static final Integer threadSzie = 10;

	@Autowired
	private  JedisSource jedisSource;

	@Autowired
	private WriteRedisService writeRedisService;

	@Autowired
	private ConfigService configService;

	@Autowired
	private IllegalTrailService illegalTrailService;

	@Autowired
	private BlackListService blackListService;

	@Autowired
	private WarnHistoryService warnHistoryService;

	@Autowired
	private FxzfSearchService fxzfSearchService;

	@Autowired
	private FxzfStaticService fxzfStaticService;


	@Autowired
	private VehicleService vehicleService;

	@Autowired
	private WarnInfoService	warnInfoService;

	@Autowired
	private ChannelService channelService;

	@Value("${fxzfdata.llen}")
	private long fxzfdata_llen;

	@Value("${static.station}")
	private String STATIC_STATION;

	@Value("${api.key}")
	private String api_key;

	@Value("${secet.key}")
	private String secet_key;


	private transient  final static String STATIC_FALG="STATIC_FLAG";


	@Override
	public redis_BoardData ReadBoardData(String detectStation) {
		Jedis jedis = null;
		redis_BoardData boardData = null;
		try {
			jedis = jedisSource.getJedis();
			logger.info("getJedis的Jedis为:"+jedis);
			String key = BoardData_Prefix + detectStation;
			if (jedis.exists(key)) {
				String result = jedis.get(key);
				DatumReader<redis_BoardData> reader = new SpecificDatumReader<redis_BoardData>( redis_BoardData.class);
				Decoder decoder = DecoderFactory.get().binaryDecoder( result.getBytes("UTF-8"), null);
				boardData = reader.read(null, decoder);
			}
		} catch (IOException e) {
			logger.error(e.toString());
		} finally {
			// 连接池对象销毁
			jedisSource.returnSource(jedis);
		}
		return boardData;
	}

	@Override
	@Transactional
	public List<redis_FxzfInfo> ReadFxzfInfo() {
		Jedis jedis = null;
		List<redis_FxzfInfo> result = new ArrayList<redis_FxzfInfo>();
		try {
			jedis = jedisSource.getJedis();
			logger.info("getJedis的Jedis为:"+jedis);
			List<String> fxzfData = jedis.blpop(0, FxzfInfo);
			redis_FxzfInfo fxzfInfo = null;
			for (String string : fxzfData) {
				if (!FxzfInfo.equals(string)) {
					DatumReader<redis_FxzfInfo> reader = new SpecificDatumReader<redis_FxzfInfo>(redis_FxzfInfo.class);
					Decoder decoder = DecoderFactory.get().binaryDecoder(string.getBytes("UTF-8"), null);
					fxzfInfo = reader.read(null, decoder);
					logger.info("====原始车头车牌："+fxzfInfo.getSHeadLicense()+"");
					logger.info("====原始车头车牌颜色："+fxzfInfo.getSHeadLicenseColor()+"");
					logger.info("====原始车头车牌地址："+fxzfInfo.getSHeadLicensePicDir()+"");
					logger.info("====原始车头车辆地址："+fxzfInfo.getSHeadCarPicDir()+"");
					result.add(fxzfInfo);
					// 将数据获取放入队列中
					fxzfQueue.put(Fxzf.translateFxzf(fxzfInfo));
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 连接池对象销毁
			jedisSource.returnSource(jedis);
		}
		return result;
	}
	
	/**
	 * 获取设备实时状态信息
	 */
	@Override
	public List<Redis_DeviceData> ReadDeviceData(String key) {
		Jedis jedis = null;
		List<Redis_DeviceData> result = new ArrayList<Redis_DeviceData>();
		try {
			jedis = jedisSource.getJedis();
			logger.info("getJedis的Jedis为:"+jedis);
			List<String> deviceDatas = jedis.blpop(0, key);
			Redis_DeviceData redisDeviceData = null;
			for(String deviceData:deviceDatas){
				if(!deviceData.equals(key)){
					DatumReader<Redis_DeviceData> reader = new SpecificDatumReader<Redis_DeviceData>(Redis_DeviceData.class);
					Decoder decoder = DecoderFactory.get().binaryDecoder(deviceData.getBytes("UTF-8"), null);
					redisDeviceData = reader.read(null, decoder);
					result.add(redisDeviceData);
				}
			}
			return result;
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	@Override
	public String RedisValueList(String License, String LicenseColor, Integer flag) {
		Jedis jedis = null;
		String result = null;
		try {
			jedis = jedisSource.getJedis();
			logger.info("getJedis的Jedis为:"+jedis);
			String key = this.writeRedisService.PatternListToRedis(License, LicenseColor, flag);
			result = jedis.get(key);
		} catch (Exception e) {
			logger.error(e.toString());
		} finally {
			// 连接池对象销毁
			jedisSource.returnSource(jedis);
		}
		return result;
	}

	@Override
	@Transactional
	public void ReceiveRealTimeData() {
		for (int i = 0; i < threadSzie; i++) {
			executorService.execute(new handler(fxzfQueue));
		}
		// 启动静态数据读取线程
		new Thread(new StaticDataReceive(fxzfQueue)).start();
		// 启动手机告警信息读取线程
		new Thread(new MsgPublish(fxzfMessage)).start();
		while (true) {
			ReadFxzfInfo();
		}
	}

	class handler implements Runnable {
		private BlockingQueue<Fxzf> fxzfQueue;
		public handler(BlockingQueue<Fxzf> fxzfQueue) {
			this.fxzfQueue = fxzfQueue;
		}
		@Override
		public void run() {
			while (true) {
				try {
					handler(fxzfQueue.take());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	class MsgPublish implements Runnable{
		private BlockingQueue<String> fxzfMessage;
		public MsgPublish(BlockingQueue<String> fxzfMessage) {
			this.fxzfMessage = fxzfMessage;
		}
		@Override
		public void run() {
			while (true){
				// 发送到手端
				try {
					String msg = fxzfMessage.take();
                    String[] channels = getChannel();
					MsgPushUtil.pushBatchAndorid(msg,channels,api_key, secet_key,3);
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		}
	}

	class StaticDataReceive implements Runnable{
		private BlockingQueue<Fxzf> fxzfQueue;
		public StaticDataReceive(BlockingQueue<Fxzf> fxzfQueue){
			this.fxzfQueue=fxzfQueue;
		}
		@Override
		public void run() {
			while(true){
				Jedis jedis = null;
				List<redis_FxzfInfo> result = new ArrayList<redis_FxzfInfo>();
				try {
					jedis = jedisSource.getJedis();
					logger.info("-----读取静态称重数据-----");
					List<String> fxzfData = jedis.blpop(0, FXZF_STATIC);
					redis_FxzfInfo fxzfInfo = null;
					for (String string : fxzfData) {
						if (!FXZF_STATIC.equals(string)) {
							DatumReader<redis_FxzfInfo> reader = new SpecificDatumReader<redis_FxzfInfo>(redis_FxzfInfo.class);
							Decoder decoder = DecoderFactory.get().binaryDecoder(string.getBytes("UTF-8"), null);
							fxzfInfo = reader.read(null, decoder);
							// 读取静态称重数据信息
							result.add(fxzfInfo);
							// 将数据获取放入队列中
							logger.info("-----读取静态称重数据,写入到缓存中-----");
							fxzfQueue.put(Fxzf.translateFxzf(fxzfInfo));
						}
					}
				} catch (Exception e) {
					logger.info("-----读取静态称重数据发生异常-----");
					e.printStackTrace();
				} finally {
					// 连接池对象销毁
					jedisSource.returnSource(jedis);
				}
			}
		}
	}

	private String[] getChannel(){
        List<Channel> channels = this.channelService.getAllChannel();
        String[] strings = new String[channels.size()];
        for(int i = 0;i<channels.size();i++){
            strings[i] = channels.get(i).getChannelId();
        }
	    return strings;
    }

	@Transactional
	public void handler(Fxzf fxzf) {
		try {
			if (null == fxzf) return;
			/** 如果时间为空设置为当前时间*/
			if(fxzf.getCaptureTime()==null){
				fxzf.setCaptureTime(new Date());
			}
			logger.info("----对接入数据进行处理---");
			if(fxzf.getDetectStation().equals(STATIC_STATION)){
				logger.info("---插入静态称重数据---");
				fxzf.setId(IDGenerator.idGenerator());
				fxzfStaticService.insert(Fxzf.convertoFxzfStatic(fxzf));
				MsgPushUtil.send(STATIC_FALG);
				this.warnHistoryService.publishToStaticQbb(fxzf);
				return;
			}
			/** 获取车重超限率和超限*/
			Double overload_percent = this.configService.getValueByCode(SysConstants.OVERLOAD_PERCENT);
			overload_percent = overload_percent!=null?overload_percent:0.0;
			Double overload_weight = this.configService.getValueByCode(SysConstants.OVERLOAD_WEIGHT);
			overload_weight = overload_weight!=null?overload_weight:0.0;
			// 设置车牌号和车牌颜色
			fxzf.setLicense(fxzf.getHeadLicense().equals("-1")?null:fxzf.getHeadLicense());
			fxzf.setLicenseColor(fxzf.getHeadLicenseColor().equals("-1")?null:fxzf.getHeadLicenseColor());
			logger.info("车牌号:"+fxzf.getLicense());
			logger.info("车牌颜色："+fxzf.getLicenseColor());
			
			if (!StringUtil.isEmpty(fxzf.getLicense())) {
				if (!writeRedisService.RedisExistsList(fxzf.getLicense(),fxzf.getLicenseColor(), 0)) {
					//判断是否超限
					if (fxzf.getOverLoadStatus() > 0) {
						//同步至车辆轨迹表
						this.illegalTrailService.syncIllegalTrail(fxzf.getLicense(), fxzf.getLicenseColor());
						//判断是否已经符合黑名单,如果符合则更新黑名单并同步至redis中
						if (this.illegalTrailService.IsAccordBlackList(fxzf.getLicense(), fxzf.getLicenseColor())) {
							this.blackListService.syncBlackList(fxzf.getLicense(), fxzf.getLicenseColor());
						}
					}
				}else {
					if (fxzf.getOverLoadStatus() > 0) {
						logger.info(fxzf.getLicense() +"同步数据至车辆轨迹表");
						this.illegalTrailService.syncIllegalTrail(fxzf.getLicense(), fxzf.getLicenseColor());
						logger.info(fxzf.getLicense() +"更新黑名单");
						this.blackListService.syncBlackList(fxzf.getLicense(),fxzf.getLicenseColor());
					}
				}
				logger.info("阈值为:W:"+overload_weight+";P:"+overload_percent);
				logger.info(fxzf.getLicense() +"判断是否超过告警阀值"+"实际值为:"+fxzf.getWeight()+";"+fxzf.getOverLoadPercent());
				if (fxzf.getOverLoadPercent()>overload_percent.doubleValue()||fxzf.getWeight()>overload_weight.doubleValue()) {
					//设置告警信息
					fxzf.setWarnFlag(1);
					//判断是否为24小时内已告警信息,如果是则入库，否则发布告警至情报板、web端，入库"
					//if (!this.warnHistoryService.IsPublishWarnMessage(fxzf.getLicense(), fxzf.getLicenseColor())) {
					logger.info(fxzf.getLicense() +"超限,发布告警至情报板、web端告警!");
					//超限发布到情报板
					fxzf.setWarnType("CHAOZAI");
						this.warnHistoryService.publishToQbb(fxzf);
					this.warnHistoryService.publishToWeb(fxzf);
					//告警信息保存到队列
					//fxzfMessage.offer(fxzf.getXxnr(),1000, TimeUnit.MILLISECONDS);


					//设置推送情报板信息
					if(!StringUtil.isEmpty(fxzf.getDetectStation())){
						WarnInfo warnInfo = new WarnInfo();
						warnInfo.setDetectStation(fxzf.getDetectStation());
						warnInfo.setWarnType(fxzf.getWarnType());
						warnInfo = this.warnInfoService.getByTempletTypeAndStation(warnInfo);
						fxzf.setXxnr(EncodeTransforUtil.getXxnrResult(this.warnHistoryService.getWarnInfo(fxzf, warnInfo),null));
					}
				} else {
					//没有超过告警阀值，但是是黑名单进行web端告警
					if (writeRedisService.RedisExistsList(fxzf.getLicense(),fxzf.getLicenseColor(), 0)) {
						logger.info(fxzf.getLicense() +"是黑名单车辆,发布web端告警");
						this.warnHistoryService.publishToWeb(fxzf);
					}else{
						logger.info(fxzf.getLicense() +"没有超载,也不是黑名单车辆不进行告警");
					}

				}
			 //非空车牌,非白名单信息
			 fxzf.setTransport(0);
			}
		//全部车牌插入
		this.fxzfSearchService.insert(fxzf);
		if(vehicleService.vehicleCount(fxzf.getLicense())>0){
			Vehicle vehicle = vehicleService.getById(fxzf.getLicense());
			if(vehicle.getAxis()!=fxzf.getAxisCount()){
				vehicle.setAxis(fxzf.getAxisCount());
				vehicleService.update(vehicle);
			}
		}else{
			Vehicle vehicle = new Vehicle();
			vehicle.setPlate(fxzf.getLicense());
			vehicle.setAxis(fxzf.getAxisCount());
			vehicleService.insert(vehicle);
		}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
